package com.lksoft.bz;

import java.io.Serializable;
import java.util.LinkedHashMap;

/**
 * Represent an arbitrarily sized stitch pattern's data
 * 
 * @author Lake
 *
 */
public class StitchPattern implements Serializable {
	private static final long serialVersionUID = 926273842182108536L;
	public final static int MAX_SIZE = 1024;
	
	/** Bead color data */
	int[][] pattern = new int[MAX_SIZE][MAX_SIZE];
	
	/** Width */
	int width = 10;
	/** Height */
	int height = 30;
	
	/** Stitch type */
	StitchType stitchType = StitchType.PEYOTE;
	
	/** rgb->bead usage */
	LinkedHashMap<Integer, BeadUsage> usedBeads = new LinkedHashMap<Integer, BeadUsage>();
	/** BeadUsage resource pool */
	LinkedHashMap<Integer, BeadUsage> usedBeadsPool = new LinkedHashMap<Integer, BeadUsage>();
	
	/**
	 * Sets a new size, preserving all consistent data and deleting all
	 * data outside the new size in case of size reduction. 
	 * 
	 * @param width The new width
	 * @param height The new height
	 */
	public void setSize(int width, int height){
		if( width < 0 || width >= MAX_SIZE || height < 0 || height > MAX_SIZE ){
			throw new IllegalArgumentException("Illegal stitch size:"+width+"x"+height);
		}
		
		int oldWidth = this.width;
		int oldHeight = this.height;
		
		this.width = width;
		this.height = height;
		
		// Clear disappeared rows
		for( int w=width; w<oldWidth; w++ ){
			for( int h=0; h<oldHeight; h++ ){
				removeBead(w, h);
			}
		}
		
		// Clear disappeared cols
		for( int h=height; h<oldHeight; h++ ){
			for( int w=0; w<oldWidth; w++ ){
				removeBead(w, h);
			}
		}
	}
	
	/**
	 * @return Pattern's width
	 */
	public int getWidth(){
		return width;
	}
	
	/**
	 * @return Pattern's height
	 */
	public int getHeight(){
		return height;
	}
	
	/**
	 * @return Color of specified position (RGB)
	 */
	public int getBead(int x, int y){
		return pattern[x][y];
	}
	
	/**
	 * Get the bead usage corresponding to the specified bead, or create
	 * and store it if not present in the pool.
	 * BeadUsage objects are guaranteed to be unique.
	 * 
	 * @param bead
	 * @return
	 */
	private BeadUsage getPoolBeadUsage(Bead bead) {
		// Return object if exists
		if( usedBeadsPool.containsKey(bead.getColor()) ) {
			return usedBeadsPool.get(bead.getColor());
		}
		
		// Create new
		BeadUsage usage = new BeadUsage(bead, 0, '\0');
		usedBeadsPool.put(bead.getColor(), usage);
		return usage;
	}
	
	/**
	 * Set a bead's color
	 * @param beadX
	 * @param beadY
	 * @param rgb
	 * @return 
	 */
	public boolean setBead(int x, int y, Bead bead) {
		boolean usedBeadsChanged = false;
		
		// Do not set same bead twice
		if( pattern[x][y] == bead.getColor() ) return false;
		
		usedBeadsChanged = removeBead(x, y);

		// Increment usage
		BeadUsage usage = usedBeads.get(bead.getColor());
		if( usage == null ){
			usage = getPoolBeadUsage(bead);
			usedBeads.put(bead.getColor(), usage);
			usedBeadsChanged = true;
		}
		usage.increment();
		
		// Set new bead
		pattern[x][y] = bead.getColor();
		
		return usedBeadsChanged;
	}

	/**
	 * Remove a bead from specified position
	 * @param x
	 * @param y
	 */
	public boolean removeBead(int x, int y){
		boolean usedBeadsChanged = false;
		
		// If no bead present, ignore
		if( pattern[x][y] == 0 ) return false;
		
		// Decrement usage
		BeadUsage usage = usedBeads.get(pattern[x][y]);
		usage.decrement();
		
		if( usage.getCount() == 0 ){
			usedBeads.remove(pattern[x][y]);
			usedBeadsChanged = true;
		}
		
		pattern[x][y] = 0;
		
		return usedBeadsChanged;
	}

	/**
	 * @return the stitchType
	 */
	public StitchType getStitchType() {
		return stitchType;
	}

	/**
	 * @param stitchType the stitchType to set
	 */
	public void setStitchType(StitchType stitchType) {
		this.stitchType = stitchType;
	}
	
	
	/**
	 * @return Used beads and their settings
	 */
	public LinkedHashMap<Integer, BeadUsage> getUsedBeads(){
		return usedBeads;
	}

}
